home *** CD-ROM | disk | FTP | other *** search
Wrap
/***************************************************************************** * File: jughead.c * * Author: Rhett "Jonzy" Jones * jonzy@cc.utah.edu * * Date: February 17, 1993 * * Modified: February 27, 1993 by Rhett "Jonzy" Jones * To support both the 'h' and 'v' flags, and to no longer * write recurrsivly to temporary files. Now I only write * to a single temporary file. * * March 3, 1993, by Rhett "Jonzy" Jones * Added support for the 'b' flag. * * March 10, 1993, by Rhett "Jonzy" Jones. * Added support for the 'B' and 'l' flags. * * March 13, 1993, by Rhett "Jonzy" Jones. * Fixed some bugs, optimized some routines, and rewrote * DoSystemCall(). Removed Lowercase() and changed calls * calls to this routine to StrToLower(), which is defined * "search.c". Modified BeenHereB4() to handle the cases * where the selector string is "/" and "1/", which is the * same as "". * * March 15, 1993, by Rhett "Jonzy" Jones. * Relocated the changes made to BeenHereB4() to a new * routine EmptyStringCheck() so all occurances of "/", * "1/", and "1" get mapped to "". I should mention I just * discovered "1" gets handled like "/", "1/", and "". Hmm. * * March 18, 1993, by Rhett "Jonzy" Jones. * Added HostField2Lower() to make sure the host field gets * mapped to lowercase, which is needed when building the * index so that sort will eliminate all duplicates. * Fixed the system call to "sort" to only sort on the selector * string and beyond. Also defined CATCOMMAND, RMCOMMAND, and * SORTCOMMAND for use when calling DoSystemCall(). * * March 21, 1993, by Rhett "Jonzy" Jones. * GetParamsFromStdin() now only prints the message informing * the user to enter control-D when finished, only if we are * getting the information from stdin and not a file. * * March 27, 1993, by Rhett "Jonzy" Jones. * Moved the definitions of VERSION, CATCOMMAND, RMCOMMAND, * SORTCOMMAND, and TMPFILENAME to the Makefile. Changed the * name of DoWeRecurse() to DoWeTraverse(). Added CantGet2Host() * nogoHead, and nogoTail to support the ability of not attempting * to connect to a host we could not connect previously. * * March 28, 1993, by Rhett "Jonzy" Jones. * Added HandleIndention(), and modified DoWeTraverse() to print * "<< see line # >>" with the proper indention if we have seen * this directory before. Added support for the -n flag. If we * received a line from a server which did not have the host or * port string, the line is now not processed. Fixed a problem of * not comparing the hosts correctly, which was fixed by converting * the incoming host name to lowercase. If a menu path has been * traversed previously, it will no longer be traversed again and a * message stating what line to view will be printed with the * proper indention. When not running to build the index table or * as a search engine, jughead now prints a note if hosts were * encountered that could not be connected to, and just prior to * termination displays the hosts it could not connect to. * * March 31, 1993, by Mic Kaczmarczik: mic@bongo.cc.utexas.edu * Added support for an optional -p port flag when running as a * search engine. Added the variable 'searchPort', modified * UsageError(), GetArguments() and the call to DoSearch() in * main(). * * April 1, 1993, by Rhett "Jonzy" Jones. * Added support for the -t flag which prints the time required * to either read in the index table, build the data file, or * process a menu from a given gopher server. Added support for * the -a and -A flags which print the dirTree with the number of * directories served or the directories served respectivly. * Made 'buildIndex' and 'doSearch' global variables instead of * local to main() and adjusted GetArguments() to reflect the * change. No longer sort the datafile to datafile.sorted when * using the -b option. Instead dataFile gets sorted into * dataFile. * * April 20, 1993, by Rhett "Jonzy" Jones. * Added LooksGood() to make sure we received a valid line of * of data from the server. This routine was written because * it was found the PC Gopher Server did not follow gopher * protocol. Added the variable menuFlag to prevent printing of * the menus when building the dataFile. Fixed a bug that would * not correctly validate the port for the exceptions host, which * is the host and port to not traverse. * * May 3, 1993, by Rhett "Jonzy" Jones. * Modified LooksGood() to immediatly return false if we acquired * a null string. This fixed a core dump when attempting to * retrieve an empty directory from a gopher+ server. Thanks * lindner@boombox.micro.umn.edu for the bug report. * * May 5, 1993, by Rhett "Jonzy" Jones. * Added support for -X which is a selector string to not traverse. * A quick hack to not traverse any selector strings that begin * with "ftp:". Example: jughead soar.cc.utah.edu -X "ftp:*". * The variable used for this support is 'exceptionSelStr' and * does supports wildcarding. * * May 20, 1993, by Rhett "Jonzy" Jones. * Moved UsageError(), PrintVersion(), GetParamsFromStdin(), and * GetArguments() to getargs.c, due in part to rewritting some of * these routines. Removed initialization of global variables at * the time of declaration, and added InitializeTheWorld() to * accommodate the initialization. Added the variable username * to support -u username and allow jughead to act as a search * engine running with a uid of username. * * May 22, 1993, by Rhett "Jonzy" Jones. * Removed the variables 'exceptionHost', 'exceptionPort', and * 'exceptionSelStr', and the routine ValidSelStr(), added the * variable 'nogos' to support multiple exception items. Thus * jughead now can support multiple hosts and ports not to traverse * as well as multiple selection strings to to traverse. * * Description: Jonzy's Universal Gopher Hierarchy Excavation And Display. * Excavates through gopher menus and displays the hierarchy * of the menus encountered. * * Routines: void HandleIndention(int indent); * short Host2Search(char *s); * List *CreateNode(char *sStr,char *hStr,char *pStr); * List *InsertNode(List *tail,List *node); * List *RemoveNode(List *tail); * short BeenHereB4(char *sStr,char *hStr,char *pStr,List *head); * short CantGet2Host(List *nogoList,char *sStr,char *Str, * char *pStr); * short DoWeTraverse(char type,char *sStr,char *hStr, * char *pStr,List *head,int indent); * void PrintPath(char *p,int indent); * void PrintItem(char *dStr,int indent); * void BuildPath(char *dStr,int indent); * void InitPath(void); * void DestroyPath(int indent); * char *EmptyStringCheck(char *sStr); * char *HostField2Lower(char *line); * int LooksGood(char **rsltLine,FILE *rdPtr); * void ProcessMenu(char *selStr,char *hostStr,char *portStr, * int indent); * void PostTime2Process(void); * void InitializeTheWorld(); * int main(int argc,char *argv[]); * * Bugs: No known bugs. * * Copyright: Copyright 1993, University of Utah Computer Center. * This source may be freely distributed as long as this copyright * notice remains intact, and is in no way used for any monetary * gain, by any institution, business, person, or persons. * * TODO: Either reenable or remove support for onlyDoHosts and * onlyDoHostsT. ****************************************************************************/ #ifdef NEXT # include <libc.h> #else # include <stdlib.h> #endif #include <signal.h> #include <stdio.h> #include <string.h> #include <sys/file.h> #include <sys/stat.h> #include <sys/wait.h> #include <time.h> #include "jughead.h" #include "dirTree.h" #include "tree.h" extern char *GetString(); /* Defined in "sockets.c". */ FILE *wtPtr, /* File pointer for writing to 'theHost'. */ *rdPtr; /* File pointer for reading from 'theHost'. */ char buffer[BUFFERSIZE], /* The output from the machine. */ path[BUFFERSIZE], /* The path to print if using 'onlyDoHostsT'. */ pathPrinted[50], /* Did we print the path(s) if using 'onlyDoHostsT'. */ *searchHosts[MAXHOSTS], /* Hosts to search. */ *initialHost, /* The initial host we connected to. */ *selStr, /* The selector string. */ *hostStr, /* The host string. */ *portStr, /* The port string. */ *fileName, /* Name of the file to open or create. */ *userName; /* Name of the user to use with -S. */ int numSearchHosts, /* The number of hosts to search. */ debug, /* Are we debugging? */ info4dirsOnly, /* Do we print host info for directories only? */ info4allItems, /* Do we print host info for all the items? */ listHosts, /* Do we print only the hosts accessed? */ listHostsNPorts, /* Do we print only the hosts and ports accessed? */ onlyDoHosts, /* Do we print info for selected hosts only? */ onlyDoHostsT, /* Same as onlyDoHosts but traverse anyway. */ buildDataFile, /* Are we building the dataFile? */ menuFlag, /* Do we display the menus? */ printLineNumbers, /* Do we print line numbers? */ searchPort, /* Default port for -S flag */ printDTree, /* Do we print the dirTree with the number of directories served? */ printDTreeDirs, /* Do we print the dirTree along with the directories served? */ time2process; /* Do we calculate the time for a certain run? */ short buildIndex, /* Do we build the index table? */ doSearch; /* Are we doing the search stuff? */ List *nogos = (List *)NIL, /* Information about who to not traverse.*/ *head = (List *)NIL, /* The head of the current menu path list. */ *tail = (List *)NIL, /* The tail of the current menu path list. */ *nogoHead = (List *)NIL,/* Head of the can't connect to host and port list. */ *nogoTail = (List *)NIL;/* Tail of the can't connect to host and port list. */ long seenDirB4; /* Have we seen this before? */ time_t startTime; /* The time a run was started, for use with 'time2process'. */ extern long lineNumber; /* Defined in dirTree.c. */ /***************************************************************************** * HandleIndention prints 'indent' number of indentions to stdout. This * routine is used to keep directory contents lined up horizontaly. ****************************************************************************/ void HandleIndention(indent) int indent; /* The level of indention. */ { int numIndents; /* The number of indentions to add to the path. */ /* Indent the data 'indent' number of indentions. */ for (numIndents = 0; numIndents < indent; numIndents++) fprintf(stdout,"%s",INDENTSTR); } /* HandleIndention */ /***************************************************************************** * Host2Search returns true if the hosts 's' is a member of 'searchHosts', * otherwise it returns false. ****************************************************************************/ short Host2Search(s) char *s; /* Is this in 'searchHosts'? */ { int i; /* A loop counter. */ for (i = 0; i < numSearchHosts; i++) if (StrRcmp(searchHosts[i],s)) /* if (!strcmp(s,searchHosts[i])) */ return(1); return(0); } /* Host2Search */ /***************************************************************************** * CreateNode returns a newly created and initialized node for the list. ****************************************************************************/ List *CreateNode(sStr,hStr,pStr) char *sStr, /* The selector string. */ *hStr, /* The host string. */ *pStr; /* The port string. */ { List *node; /* The node we are returning. */ if (node = (List *)malloc(sizeof(List))) if (node->info.sStr = (char *)malloc(strlen(sStr) + 1)) { strcpy(node->info.sStr, sStr); if (node->info.hStr = (char *)malloc(strlen(hStr) + 1)) { strcpy(node->info.hStr, hStr); if (node->info.pStr = (char *)malloc(strlen(pStr) + 1)) { strcpy(node->info.pStr, pStr); node->next = node->last = (List *)NIL; return(node); } else { free(node->info.hStr); node->info.hStr = (char *)NIL; free(node->info.sStr); node->info.sStr = (char *)NIL; free(node); node = (List *)NIL; } } else { free(node->info.sStr); node->info.sStr = (char *)NIL; free(node); node = (List *)NIL; } } else { free(node); node = (List *)NIL; } fprintf(stderr,"error: CreateNode could not get memory for the node.\n"); return(node); } /* CreateNode */ /***************************************************************************** * InsertNode inserts the node 'node' on the end of the list 'list'. ****************************************************************************/ List *InsertNode(tail,node) List *tail, /* The tail of the list we are inserting into. */ *node; /* The node we are inserting. */ { if (!node) return(tail); tail->next = node; node->last = tail; return(node); } /* InsertNode */ /***************************************************************************** * RemoveNode removes and frees up the memory occupied by the last item * in the list, which is pointed to by 'tail'. ****************************************************************************/ List *RemoveNode(tail) List *tail; /* The tail of the list we are inserting into. */ { List *node; /* The node to remove. */ node = tail; tail = tail->last; tail->next = (List *)NIL; free(node->info.sStr); node->info.sStr = (char *)NIL; free(node->info.hStr); node->info.hStr = (char *)NIL; free(node->info.pStr); node->info.pStr = (char *)NIL; free(node); node = (List *)NIL; return(tail); } /* RemoveNode */ /***************************************************************************** * BeenHereB4 returns true if 'sStr', 'hStr', and 'pStr' are in the list * pointed to by 'list'. This is done so we will not travese a menu * we are already looking at. Otherwise it returns false because we * are not looking at nor have been in this part of the tree. ****************************************************************************/ short BeenHereB4(sStr,hStr,pStr,list) char *sStr, /* The selector string. */ *hStr, /* The host string. */ *pStr; /* The port string. */ List *list; /* Head of the list. */ { while (list) /* See if we have been here before. */ { if (!strcmp(list->info.sStr,sStr)) if (!strcmp(list->info.hStr,hStr)) if (!strcmp(list->info.pStr,pStr)) return(1); list = list->next; } return(0); } /* BeenHereB4 */ /***************************************************************************** * CantGet2Host returns true if we could not connect to 'hStr' out port 'pstr' * previously. Otherwise it returns false. This routine calls BeenHereB4() * and was written for readability only. ****************************************************************************/ short CantGet2Host(nogoList,sStr,hStr,pStr) List *nogoList; /* List of hosts we can't connect to. */ char *sStr, /* The selector string. */ *hStr, /* The host to connect to. */ *pStr; /* The port to use. */ { return(BeenHereB4(sStr,hStr,pStr,nogoList)); } /* CantGet2Host */ /***************************************************************************** * DoWeTraverse returns true if we can look at this directory in the menu. * Otherwise it returns false. In otherwords return true if the item we * have not looked at this directory yet, and the current entry is a * directory, and the directory is from one of the hosts contained in * 'hosts2search'. ****************************************************************************/ short DoWeTraverse(type,sStr,hStr,pStr,list,indent) char type, /* What type of entry is this? */ *sStr, /* The selector string. */ *hStr, /* The host string. */ *pStr; /* The port string. */ List *list; /* Head of the list. */ int indent; /* The level to indent if need be. */ { List *t; /* A temporary list of nogos.*/ char *asterik; /* Where is the asterik? */ size_t numChars; /* Number of characters to the asterik. */ for (t = nogos; t; t = t->next) if (t->info.sStr[0]) { if (asterik = strchr(t->info.sStr,'*')) numChars = (size_t)(asterik - t->info.sStr); else numChars = strlen(t->info.sStr); if (!strncmp(t->info.sStr,sStr,numChars)) return(0); } else if (t->info.hStr) { if (!strcmp(hStr,t->info.hStr) && !strcmp(pStr,t->info.pStr)) return(0); } #if(1) /* The NEW way. */ WaterTree(sStr,hStr,pStr); if (type == A_DIRECTORY && Host2Search(hStr)) if (!(seenDirB4 = InDirTree(dirRoot,PSTR))) { dirRoot = BuildDirTree(dirRoot); return(1); } else if (menuFlag) { HandleIndention(indent + 2 * printLineNumbers); fprintf(stdout,"<< see line %ld >>\n",seenDirB4),++lineNumber; } #else if (type == A_DIRECTORY) if (Host2Search(hStr) || (onlyDoHostsT && !strcmp(initialHost,hStr))) return(!BeenHereB4(sStr,hStr,pStr,list)); #endif return(0); } /* DoWeTraverse */ /***************************************************************************** * PrintPath prints the pathway, with the proper number of indentions for * an item that has not had the pathway printed. ****************************************************************************/ void PrintPath(p,indent) char *p; /* The path to print. */ int indent; /* The indention level. */ { char *s; /* The string to print out. */ int i,j; /* Loop counters. */ short gotOne = 0; /* Do we have a directory to print? */ /* Find the directory we need to start printing if we have one. */ for (i = 0; i < indent; i++) if (pathPrinted[i] == NOPE) { gotOne = 1; break; } if (gotOne) /* Print the pathway. */ { /* Skip pathways that have been printed. */ for (j = 0, s = p; j < i; j++) { for ( ; *s && *s != '\t'; s++) ; if (*s) s++; } /* Print the unprinted pathway(s). */ for ( ; i < indent; i++) { if (i) /* Indent the directory. */ fprintf(stdout,"%s",INDENTSTR); for ( ; *s && *s != '\t'; s++) fprintf(stdout,"%c",*s); if (*s) s++; pathPrinted[i] = YEP; fprintf(stdout,"/\n"),++lineNumber; } } } /* PrintPath */ /***************************************************************************** * PrintItem prints the item with the proper number of indentions, as well * as prints what type of item it is just like the unix gopher from Minnesota. ****************************************************************************/ void PrintItem(dStr,indent) char *dStr; /* The display string. */ int indent; /* The level of indention. */ { if (printLineNumbers) /* User wants the line numbers printed. */ fprintf(stdout,"%7ld ",lineNumber + 1); HandleIndention(indent); /* Print the menu title like a gopher menu. */ fprintf(stdout,"%s",dStr + 1); switch (dStr[0]) { case A_DIRECTORY: fprintf(stdout,"/"); if (onlyDoHostsT) pathPrinted[indent] = YEP; break; case A_CSO: fprintf(stdout," <CSO>"); break; case A_TN3270: fprintf(stdout," <3270>"); break; case A_TELNET: fprintf(stdout," <TEL>"); break; case A_INDEX: fprintf(stdout," <?>"); break; case A_SOUND: fprintf(stdout," <)"); break; case A_FILE: fprintf(stdout,"."); break; case A_PCBIN: fprintf(stdout," <PC Bin>"); break; case A_UNIXBIN: fprintf(stdout," <Bin>"); break; case A_IMAGE: case A_GIF: fprintf(stdout," <Picture>"); break; case A_MACHEX: fprintf(stdout," <HQX>"); break; default: fprintf(stdout," <~%c~>",dStr[0]); break; } } /* PrintItem */ /***************************************************************************** * BuildPath builds the pathways for items so we can print the items with * the pathway when the 'O' option is used. ****************************************************************************/ void BuildPath(dStr,indent) char *dStr; /* The string to add to the path. */ int indent; /* The level of indention. */ { if (indent) strcat(path,"\t"); strcat(path,dStr); } /* BuildPath */ /***************************************************************************** * InitPath resets the all path variables to zero. ****************************************************************************/ void InitPath() { int i; for (i = 0; i < 50; i++) pathPrinted[i] = NOPE; path[0] = '\0'; } /* InitPath */ /***************************************************************************** * DestroyPath destroys the last path within the pathway to an item. ****************************************************************************/ void DestroyPath(indent) int indent; /* The level of indention. */ { char *s; /* A pointer into 'path'. */ if (!indent) InitPath(); else if ((s = strrchr(path,'\t')) > path) { *s = '\0'; pathPrinted[indent] = NOPE; } } /* DestroyPath */ /***************************************************************************** * EmptyStringCheck checks if the string 'sStr' is either "/", "1/", or "1", * and if it is we return the emptystring "". Otherwise 'sStr' gets returned * unchanged. The reason for this routine is to prevent a recursive menu * loop from happening. The gopher protocol says you must send the empty * string to acquire the menu. Well it looks like a unix server handles * "", "/", "1/", and "1" all the same. Hmm. ****************************************************************************/ static char *EmptyStringCheck(sStr) char *sStr; /* The string we are testing. */ { if (!strcmp(sStr,"/") || !strcmp(sStr,"1/") || !strcmp(sStr,"1")) return(EMPTYSTRING); return(sStr); } /* EmptyStringCheck */ /***************************************************************************** * HostField2Lower returns the string passed in with the host field converted * to lowercase. ****************************************************************************/ char *HostField2Lower(line) char *line; /* The line we are looking at. */ { char *s; /* A position in 'line'. */ for (s = strchr(strchr(line,'\t') + 1,'\t') + 1; *s && *s != '\t'; s++) *s = tolower(*s); return(line); } /* HostField2Lower */ /***************************************************************************** * LooksGood returns true if we received a valid line from 'rdPtr', otherwise * it returns false. A valid line has the form: * dStr\tsStr\thStr\tpStr[\tmore]\r\n * a invalid line, or we are done, has the form: * .\r\n * or any line with no tabs, etc. * This routine was written because the PC Gopher server does not follow * gopher protocol, and sends the string: * Error: Could not find requested file\r\n.\r\n * when it should look something like: * Error: could not find requested file\t\terror.host\t-1\r\n.\r\n ****************************************************************************/ static int LooksGood(rsltLine,rdPtr) char **rsltLine; /* The line we are getting from 'rdPtr'. */ FILE *rdPtr; /* The file or socket we are reading from. */ { char *s; /* A position in 'rsltLine'. */ int numTabs; /* How many tabs are there? */ /* Get the line of data from the server and make sure we got something. */ if (!(*rsltLine = GetString(rdPtr))) return(0); /* Check of we are done. */ if (strstr(rsltLine,".\r")) return(0); /* See if we have at least 3 tabs. */ for (s = *rsltLine, numTabs = 0; *s; s++) if (*s == '\t') numTabs++; if (numTabs > 2) return(1); /* We got something that is totaly out to lunch. */ return(0); } /* LooksGood */ /***************************************************************************** * ProcessMenu processes the menu entity which should be a directory. If * the entity is not a directory ... well you know what they say, "garabage * in ... garbage out. * This code is ugly, but oh well such is life. ****************************************************************************/ void ProcessMenu(selStr,hostStr,portStr,indent) char *selStr, /* Selection string to send. */ *hostStr, /* The host to contact. */ *portStr; /* The port to use. */ int indent; /* The level of indentation. */ { char **data, /* The data acquired from the host via the file. */ *rsltLine, /* The resultant line of data. */ *dStr, /* The display field. */ *sStr, /* The selector field. */ *hStr, /* The host field. */ *pStr; /* The port field. */ FILE *fPtr; /* Pointer to the menu file. */ int numItems, /* Number of items in the menu. */ error = 0, /* Did we encounter an error? */ i; /* A loop counter. */ if (!head) head = tail = CreateNode(selStr,hostStr,OnlyDigits(portStr)); else tail = InsertNode(tail,CreateNode(selStr,hostStr,OnlyDigits(portStr))); if (!dirRoot && !indent) { WaterTree(selStr,hostStr,portStr); indent++; lineNumber++; if (menuFlag && printLineNumbers) /* User wants the line numbers printed. */ fprintf(stdout,"%7ld ",lineNumber); fprintf(stdout,"Gopher root is [%s] port = %s\n",hostStr,portStr); dirRoot = BuildDirTree(dirRoot); } if (ContactHost(hostStr,Str2Int(portStr))) { /* Write the information to a temporary file. */ if (fPtr = fopen(TMPFILENAME,"w")) { SendString(selStr); SendString("\r\n"); for (numItems = 0; LooksGood(&rsltLine,rdPtr); numItems++) fprintf(fPtr,"%s",(buildDataFile) ? HostField2Lower(rsltLine) : rsltLine); CloseReadNwriter(); fclose(fPtr); if (buildDataFile) DoSystemCall(Mysprint(CATCOMMAND,TMPFILENAME,fileName)); if (debug) fprintf(stderr,"Connections are now closed with %d item%c found\n", numItems,numItems > 1 ? 's' : '\0'); } else error = fprintf(stderr,"error: ProcessMenu cannot create [%s]\n",TMPFILENAME); /* Read the temporary file into a dynamic array. */ if (!error && (data = (char **)malloc(numItems * sizeof(char *)))) { if (fPtr = fopen(TMPFILENAME,"r")) { for (i = 0; i < numItems && !error; i++) if (data[i] = (char *)malloc((strlen(rsltLine = GetString(fPtr)) + 1) * sizeof(char))) strcpy(data[i],rsltLine); else { error = fprintf(stderr,"error: ProcessMenu cannot get memory for the %dth element\n"); for ( ; i; i--) free(data[i]); free(data); } fclose(fPtr); DoSystemCall(Mysprint(RMCOMMAND,TMPFILENAME)); } else error = fprintf(stderr,"error: ProcessMenu cannot read [%s]\n",TMPFILENAME); } else if (!error && numItems) error = fprintf(stderr,"error: ProcessMenu cannot get memory for the %d data items\n",numItems); if (!error) { for (i = 0; i < numItems; i++) { dStr = MyStrTok(data[i],'\t'); sStr = EmptyStringCheck(MyStrTok(NULL,'\t')); hStr = StrToLower(MyStrTok(NULL,'\t')); pStr = OnlyDigits(MyStrTok(NULL,'\0')); /* Make sure we were able to parse the line correctly. */ if (!hStr[0] || !pStr[0]) /* Yipes! Skip this item. */ continue; if (debug) { fprintf(stderr,"\tdStr = [%s]\n",dStr); fprintf(stderr,"\tsStr = [%s]\n",sStr); fprintf(stderr,"\thStr = [%s]\n",hStr); fprintf(stderr,"\tpStr = [%s]\n",pStr); } if (listHosts) { char s[1024]; sprintf(s,"%s\t%s",hStr,pStr); BuildTree(&root,s,-1); } else if (menuFlag && (!onlyDoHosts || (onlyDoHosts && Host2Search(hStr)))) { if (onlyDoHostsT) PrintPath(path,indent); PrintItem(dStr,indent); /* Do we print the host and port to the right of the item? */ if (info4allItems || (info4dirsOnly && dStr[0] == A_DIRECTORY)) fprintf(stdout,"\t%s %s",hStr,pStr); fprintf(stdout,"\n"),++lineNumber; } if (DoWeTraverse(dStr[0],sStr,hStr,pStr,head,indent + 1)) { if (!listHosts && onlyDoHostsT) BuildPath(dStr + 1,indent); if (!CantGet2Host(nogoHead,EMPTYSTRING,hStr,pStr)) ProcessMenu(sStr,hStr,pStr,indent + 1); else fprintf(stderr,"warning: ProcessMenu could not previously connect to %s %s\n",hStr,pStr); if (!listHosts && onlyDoHostsT) DestroyPath(indent); } } /* Free up the memory we acquired. */ for (i = 0; i < numItems; i++) free(data[i]); free(data); } } else /* Keep track of hosts we can't connect to. */ { if (!nogoHead) nogoHead = nogoTail = CreateNode(EMPTYSTRING,hostStr,portStr); else nogoTail = InsertNode(nogoTail,CreateNode(EMPTYSTRING,hostStr,portStr)); } if (head != tail) tail = RemoveNode(tail); } /* ProcessMenu */ /***************************************************************************** * PostTime2Process ****************************************************************************/ void PostTime2Process() { time_t theTime, /* The current time. */ timeUsed; /* The time in seconds required for a given run. */ int hours, /* The hours for the process. */ minutes, /* The minutes for the process. */ seconds; /* The seconds for the process. */ time(&theTime); timeUsed = theTime - startTime; if (doSearch) fprintf(stderr,"The time required to load the index table took "); else if (buildIndex) fprintf(stderr,"The time required to build the index table took "); else fprintf(stderr,"The time required to process the menus of %s took ",initialHost); hours = (int)(timeUsed / 3600); timeUsed -= hours * 3600; minutes = (int)(timeUsed / 60); timeUsed -= minutes * 60; seconds = (int)timeUsed; fprintf(stderr,"%d:%d:%d\n",hours,minutes,seconds); } /* PostTime2Process */ /***************************************************************************** * InitializeTheWorld initializes the global variables to either 0, NIL, or * the respective default value. ****************************************************************************/ void InitializeTheWorld() { initialHost = selStr = hostStr = portStr = fileName = userName = logFile = (char *)NIL; numSearchHosts = debug = info4dirsOnly = info4allItems = listHosts = listHostsNPorts = onlyDoHosts = onlyDoHostsT = buildDataFile = printLineNumbers = printDTree = printDTreeDirs = time2process = buildIndex = doSearch = 0; menuFlag = 1; searchPort = PORT2USE; selStr = EMPTYSTRING; portStr = DEFAULTPORT; head = tail = nogoHead = nogoTail = (List *)NIL; } /* InitializeTheWorld */ /***************************************************************************** * main is the heart of this program. ****************************************************************************/ int main(argc,argv) int argc; char *argv[]; { InitializeTheWorld(); if (GetArguments(argc,argv,&fileName,&logFile)) if (doSearch) DoSearch(fileName,logFile,searchPort); /* Never returns. */ else { if (time2process) time(&startTime); if (buildIndex) if (CreateWordsTree(fileName)) MakeHashTables(fileName,root); else exit(-1); else { ProcessMenu(selStr,hostStr,portStr,FIRSTMENU); if (buildDataFile) { fprintf(stderr,"Removing any duplicates from [%s].\n",fileName); DoSystemCall(Mysprint(SORTCOMMAND,fileName,fileName)); } if (listHosts || listHostsNPorts) PrintTree(root,listHosts + listHostsNPorts); if (printDTree) { fprintf(stderr,"********************************************\n"); fprintf(stderr,"Now printing the directory tree with the "); if (printDTreeDirs) fprintf(stderr,"directories being served.\n"); else fprintf(stderr,"number of directories served.\n"); PrintDirTree(dirRoot,PSTR); fprintf(stderr,"********************************************\n"); } if (nogoHead) { fprintf(stderr,"\nNote: Could not connect to the following host(s):\n"); while (nogoHead) { fprintf(stderr," %s %s\n",nogoHead->info.hStr,nogoHead->info.pStr); nogoHead = nogoHead->next; } } if (buildDataFile) fprintf(stderr,"[%s] now contains the information with duplicates removed\nand points to %ld different gopher menu items\n",fileName,NumberOfLines(fileName)); } if (time2process) PostTime2Process(); } exit(0); } /* main */